package com.edward.puff.aop;

import com.alibaba.fastjson.JSONArray;
import com.edward.puff.config.PuffConfiguration;
import com.edward.puff.config.PuffMetadata;
import com.edward.puff.execute.PuffExecutor;
import com.edward.puff.repository.PuffTransLog;
import com.edward.puff.repository.TransLogRepository;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import javax.annotation.Resource;
import java.lang.reflect.Method;

/**
 * @Author: Edward
 * @Date: 2019/11/27 下午4:31
 * <p>
 * 拦截@Puff修饰方法,把同步分布式调用->本地事务+异步分布式调用
 */
@Aspect
@Slf4j
public class PuffAspect {

    @Resource
    private PuffConfiguration puffConfig;

    @Resource
    private PuffExecutor puffExecutor;

    /**
     * 切点:所有@Puff修饰的方法
     * <p>
     * 1.获取调用方法的aop基本信息，封装record
     * 2.同步事务中，将record记录插入本地数据库
     * 3.注册同步事务处理器：afterCommit 执行真是的分布式业务
     */
    @Around(value = "@annotation(com.edward.puff.annotation.Puff)")
    public void txRecord(ProceedingJoinPoint joinPoint) {
        //如果当前线程不在事务中，抛出异常
        if (!TransactionSynchronizationManager.isSynchronizationActive()) {
            throw new RuntimeException("no transaction in current require");
        }
        //build txLog
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        PuffMetadata meta = puffConfig.getPuffMetadata(method.toGenericString());
        PuffTransLog txLog = new PuffTransLog().setTxLogId((String) joinPoint.getArgs()[meta.getTxIdIndex()])
                .setSignature(meta.getSignature()).setCurParams(JSONArray.toJSONString(joinPoint.getArgs()));
        //save
        TransLogRepository repository = meta.getRepositoryClass() == null
                ? puffConfig.getGlobalRepository() : puffConfig.getBean(meta.getRepositoryClass());
        repository.saveTransLog(txLog);
        //注册自定义事务处理器
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
            @Override
            public void afterCommit() {
                puffExecutor.asyncExecute(txLog);
            }
        });
    }
}
